[0-3] long Current Date-time on Server's clock [4] byte Number of Volumes that follow ----> byte NumVol Structure... Msb = HasPassword (bit) Lsb = HasConfigInfo (appleII stuff, ignore it) P-String Volume Name <----
The string is repeated for each volume.
There is also an example in the February 1995 Developer CD:
Dev.CD Feb 95:Sample Code:Snippets:Networking:AppleTalk Libraries
The string from this example looks like this:
short LogOnAsGuest(AddrBlock *serverAddress,Ptr SCBBlock) { AFPLoginPrm *XPPBlock; /* to build parameter blocks for AFP */ short cbsize; char XPPReply[quantumSize*8]; /* used to get AFP replies (max. size 8 ATP packet) */ char XPPCmd[quantumSize]; /* used to send AFP commands */ OSErr error; short result; - /* information used by Login function */ char AFPVersion[30]; char AuthentMethod[30]; strcpy(AFPVersion, "AFPVersion 2.0"); strcpy(AuthentMethod, "No User Authent"); if (!(XPPBlock = (AFPLoginPrm *)NewPtrClear(sizeof(AFPLoginPrm)))) return MemError(); XPPBlock->ioRefNum = xppRefNum; XPPBlock->ioCompletion = nil; XPPBlock->aspTimeout = 1; /* Timeout for ATP */ XPPBlock->aspRetry = 2; /* Retry count for ATP */ XPPBlock->afpAddrBlock = *serverAddress; /* AppleTalk address of the server */ XPPBlock->afpAttnRoutine = nil ; XPPBlock->rbPtr = (Ptr)XPPReply; /* Reply buffer pointer */ XPPBlock->rbSize = quantumSize; /* Reply buffer size */ /* prepare command information : 1st byte : command (login) 2nd Pascal string : AFP version 3rd Pascal string : Authentication Method - see Inside AppleTalk 13-104 */ XPPCmd[0] = afpLogin; XPPCmd[1] = strlen(AFPVersion); strcpy(XPPCmd+2,AFPVersion); cbsize = strlen(XPPCmd); XPPCmd[cbsize] = strlen(AuthentMethod); strcpy(XPPCmd+cbsize+1,AuthentMethod); cbsize = strlen(XPPCmd); XPPBlock->cbPtr = (Ptr)XPPCmd; /* Command block pointer */ XPPBlock->cbSize = cbsize; XPPBlock->afpSCBPtr = (Ptr) SCBBlock; /* SCB pointer in AFP login */ if ((error = AFPCommand((XPPParmBlkPtr)XPPBlock,sync)) != noErr) result = error; else if (XPPBlock->cmdResult != noErr) result = XPPBlock->cmdResult ; else result = XPPBlock->sessRefnum; /* return session number */ DisposPtr((Ptr)XPPBlock); return result; } /* LogOnAsGuest */ OSErr GetServerParams(short sessNum,Ptr replyBuffer,short buffLength) { XPPPrmBlk *XPPBlock; /* to build parameter blocks for AFP */ char XPPCmd[quantumSize];/* used to send AFP commands */ OSErr error; if (!(XPPBlock = (XPPPrmBlk *)NewPtrClear(sizeof(XPPPrmBlk)))) return MemError(); XPPBlock->ioRefNum = xppRefNum; /* driver reference number */ /* prepare command information : no input provided except command - see IA 13-98 */ XPPCmd[0] = afpGetSParms; XPPBlock->sessRefnum = sessNum; XPPBlock->aspTimeout = 2; /* Timeout for ATP */ XPPBlock->aspRetry = 2; XPPBlock->cbPtr = (Ptr)XPPCmd; XPPBlock->cbSize = 1; /* Command block size */ XPPBlock->rbPtr = replyBuffer; /* Reply buffer pointer */ XPPBlock->rbSize = buffLength; XPPBlock->wdSize = 0; /* Write Data size */ XPPBlock->wdPtr = nil; /* Write Data pointer */ error = AFPCommand((XPPParmBlkPtr)XPPBlock,sync); DisposPtr((Ptr)XPPBlock); return error; } main() { Str32 theServer; Ptr buffer; AddrBlock serverAddress; char SCBBlock[scbMemSize]; /* used by AFP to manage a session */ short sessionNum; OSErr ErrNo; short refNum; /* allocate a buffer to retrieve info */ if (!(buffer = NewPtr(buffSize))) return; /* open .XPP driver */ ErrNo = OpenXPP(&refNum); // hard coded address cause I'm lazy serverAddress.aNet = 41107; serverAddress.aNode = 87; serverAddress.aSocket = 250; // simple login as guest if ((sessionNum = LogOnAsGuest(&serverAddress,&SCBBlock)) <= 0) { DisposePtr(buffer); return; } // get server params if ((ErrNo = GetServerParams(sessionNum,buffer,buffSize)) != noErr) { DisposePtr(buffer); return; } // buffer has server string // be a good citizen LogOut(sessionNum,&SCBBlock); DisposePtr(buffer); }